#ifndef STATE_H_
#define STATE_H_

#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <stdint.h>

#include "Timer.h"
#include "Bug.h"
#include "Square.h"
#include "Map.hh"

/*
    constants
*/
const char CDIRECTIONS[4] = {'N', 'E', 'S', 'W'};

/*
    struct to store current state information
*/
struct State
{
    /*
        Variables
    */
    int rows, cols,
        turn, turns,
        noPlayers;
    double attackradius, spawnradius, viewradius;
    double loadtime, turntime;
    std::vector<double> scores;
    bool gameover;
    int64_t seed;

    Map * map;
  std::vector<uLocation> myAnts, enemyAnts, myHills, enemyHills, food;
    unsigned my_team;
    unsigned hive, guards;
	

    /// remember ant current direction
    std::map<uLocation,int> last_aim;

    Timer timer;

    /*
        Functions
    */
    State();
    State(const char *fname);
    ~State();

    void setup();
    void reset();

    Map & grid()
    {
        if(map == NULL) {
            ASSERT(map);
            map=new Map(0,0,0,0,0);
        }
        return *map;
    }
    Map & grid() const
    {
        if(map == NULL) {
            ASSERT(map);
            const_cast<State*>(this)->map=new Map(0,0,0,0,0);
        }
        return *map;
    }

    Square & location(uLocation loc)
    {
        if (loc < grid().rows * grid().cols)
            return grid()[loc];
        else
        {
            ASSERT(loc < grid().rows * grid().cols);
            return grid()[0];
        }
    }

    void makeMove(const uLocation &loc, int direction);

    void simulateMove(const uLocation &loc, uLocation to);

    //returns the new location from moving in a given direction with the edges wrapped
    uLocation getLocation(const uLocation &startLoc, int direction)
    {
        return grid().getLocation(startLoc, direction);
    }

    //returns the euclidean distance between two locations with the edges wrapped
    inline double distance(const uLocation &loc1, const uLocation &loc2)
    {
        return grid().distance(loc1,loc2);
    }

    void updateVisionInformation();

};

std::ostream& operator<<(std::ostream &os, const State &state);
std::istream& operator>>(std::istream &is, State &state);

#endif //STATE_H_
